﻿using System;
using System.Collections.Generic;
using GeoAPI.Geometries;
using YJKGridTopologyCal.Utilities;

namespace YJKGridTopologyCal.Geometries
{
	[Serializable]
	public class Point : Geometry, IPoint, IGeometry, ICloneable, IComparable, IComparable<IGeometry>, IEquatable<IGeometry>, IPuntal
	{
		public ICoordinateSequence CoordinateSequence
		{
			get
			{
				return this._coordinates;
			}
		}

		public Point(Coordinate coordinate) : this(GeometryFactory.Default.CoordinateSequenceFactory.Create(new Coordinate[]
		{
			coordinate
		}), GeometryFactory.Default)
		{
		}

		public Point(ICoordinateSequence coordinates, IGeometryFactory factory) : base(factory)
		{
			if (coordinates == null)
			{
				coordinates = factory.CoordinateSequenceFactory.Create(new Coordinate[0]);
			}
			Assert.IsTrue(coordinates.Count <= 1);
			this._coordinates = coordinates;
		}

		public override Coordinate[] Coordinates
		{
			get
			{
				if (!this.IsEmpty)
				{
					return new Coordinate[]
					{
						this.Coordinate
					};
				}
				return new Coordinate[0];
			}
		}

		public override double[] GetOrdinates(Ordinate ordinate)
		{
			if (this.IsEmpty)
			{
				return new double[0];
			}
			Ordinates ordinates = OrdinatesUtility.ToOrdinatesFlag(new Ordinate[]
			{
				ordinate
			});
			if ((this._coordinates.Ordinates & ordinates) != ordinates)
			{
				return new double[]
				{
					double.NaN
				};
			}
			return new double[]
			{
				this._coordinates.GetOrdinate(0, ordinate)
			};
		}

		public override int NumPoints
		{
			get
			{
				if (!this.IsEmpty)
				{
					return 1;
				}
				return 0;
			}
		}

		public override bool IsEmpty
		{
			get
			{
				return this._coordinates.Count == 0;
			}
		}

		public override Dimension Dimension
		{
			get
			{
				return Dimension.Point;
			}
		}

		public override Dimension BoundaryDimension
		{
			get
			{
				return Dimension.False;
			}
		}

		public double X
		{
			get
			{
				if (this.Coordinate == null)
				{
					throw new ArgumentOutOfRangeException("X called on empty Point");
				}
				return this.Coordinate.X;
			}
			set
			{
				this.Coordinate.X = value;
			}
		}

		public double Y
		{
			get
			{
				if (this.Coordinate == null)
				{
					throw new ArgumentOutOfRangeException("Y called on empty Point");
				}
				return this.Coordinate.Y;
			}
			set
			{
				this.Coordinate.Y = value;
			}
		}

		public override Coordinate Coordinate
		{
			get
			{
				if (this._coordinates.Count == 0)
				{
					return null;
				}
				return this._coordinates.GetCoordinate(0);
			}
		}

		public override string GeometryType
		{
			get
			{
				return "Point";
			}
		}

		public override OgcGeometryType OgcGeometryType
		{
			get
			{
				return OgcGeometryType.Point;
			}
		}

		public override IGeometry Boundary
		{
			get
			{
				return base.Factory.CreateGeometryCollection(null);
			}
		}

		protected override Envelope ComputeEnvelopeInternal()
		{
			if (this.IsEmpty)
			{
				return new Envelope();
			}
			return new Envelope(this.Coordinate.X, this.Coordinate.X, this.Coordinate.Y, this.Coordinate.Y);
		}

		public override bool EqualsExact(IGeometry other, double tolerance)
		{
			return this.IsEquivalentClass(other) && ((this.IsEmpty && other.IsEmpty) || (this.IsEmpty == other.IsEmpty && Geometry.Equal(other.Coordinate, this.Coordinate, tolerance)));
		}

		public override void Apply(ICoordinateFilter filter)
		{
			if (this.IsEmpty)
			{
				return;
			}
			filter.Filter(this.Coordinate);
		}

		public override void Apply(ICoordinateSequenceFilter filter)
		{
			if (this.IsEmpty)
			{
				return;
			}
			filter.Filter(this._coordinates, 0);
			if (filter.GeometryChanged)
			{
				base.GeometryChanged();
			}
		}

		public override void Apply(IGeometryFilter filter)
		{
			filter.Filter(this);
		}

		public override void Apply(IGeometryComponentFilter filter)
		{
			filter.Filter(this);
		}

		public override object Clone()
		{
			Point point = (Point)base.Clone();
			point._coordinates = (ICoordinateSequence)this._coordinates.Clone();
			return point;
		}

		public override IGeometry Reverse()
		{
			return (IGeometry)this.Clone();
		}

		public override void Normalize()
		{
		}

		protected internal override int CompareToSameClass(object other)
		{
			Point point = (Point)other;
			return this.Coordinate.CompareTo(point.Coordinate);
		}

		protected internal override int CompareToSameClass(object other, IComparer<ICoordinateSequence> comparer)
		{
			return comparer.Compare(this.CoordinateSequence, ((IPoint)other).CoordinateSequence);
		}

		public Point(double x, double y, double z) : this(Geometry.DefaultFactory.CoordinateSequenceFactory.Create(new Coordinate[]
		{
			new Coordinate(x, y, z)
		}), Geometry.DefaultFactory)
		{
		}

		public Point(double x, double y) : this(Geometry.DefaultFactory.CoordinateSequenceFactory.Create(new Coordinate[]
		{
			new Coordinate(x, y)
		}), Geometry.DefaultFactory)
		{
		}

		public double Z
		{
			get
			{
				if (this.Coordinate == null)
				{
					throw new ArgumentOutOfRangeException("Z called on empty Point");
				}
				return this.Coordinate.Z;
			}
			set
			{
				this.Coordinate.Z = value;
			}
		}

		public double M
		{
			get
			{
				if (this.CoordinateSequence == null)
				{
					throw new ArgumentOutOfRangeException("M called on empty Point");
				}
				return this.CoordinateSequence.GetOrdinate(0, Ordinate.M);
			}
			set
			{
				this.CoordinateSequence.SetOrdinate(0, Ordinate.M, value);
			}
		}

		private static readonly Coordinate EmptyCoordinate = null;

		public static readonly IPoint Empty = new GeometryFactory().CreatePoint(Point.EmptyCoordinate);

		private ICoordinateSequence _coordinates;
	}
}
